package com.lambkit.core.event;

import cn.hutool.core.thread.ExecutorBuilder;
import cn.hutool.log.Log;
import com.lambkit.core.event.annotation.Listener;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;

/**
 * @author yangyong(孤竹行)
 */
public class EventDispatcher implements IEventDispatcher {

    private static final Log log = Log.get(EventDispatcher.class);
    private final ExecutorService threadPool;
    private final Map<String, IEventBus> asyncListenerMap;
    private final Map<String, IEventBus> listenerMap;
    public static final String defaultEventId = "default";

    public EventDispatcher() {
        //获取系统处理器个数，作为线程池数量
        //int nThreads = Runtime.getRuntime().availableProcessors();
        threadPool = ExecutorBuilder.create().build();
        asyncListenerMap = new ConcurrentHashMap<String, IEventBus>();
        listenerMap = new ConcurrentHashMap<String, IEventBus>();
        //eventBusMap.put(defaultEventId, new EventBus());
        //asyncEventBusMap.put(defaultEventId, new AsyncEventBus(threadPool));
    }

    @Override
    public void register(Class<? extends IEventListener> listenerClass) {
        if (listenerClass == null) {
            return;
        }

        Listener listenerAnnotation = listenerClass.getAnnotation(Listener.class);
        if (listenerAnnotation == null) {
            log.warn("listenerClass[" + listenerAnnotation + "] resigter fail,because not use Listener annotation.");
            return;
        }

        String[] actions = listenerAnnotation.action();
        if (actions == null || actions.length == 0) {
            log.warn("listenerClass[" + listenerAnnotation + "] resigter fail,because action is null or blank.");
            return;
        }

        for (String action : actions) {
            IEventBus eventBus = null;
            if (listenerAnnotation.async()) {
                eventBus = asyncListenerMap.get(action);
                if (null == eventBus) {
                    eventBus = new AsyncEventBus(threadPool);
                }
                asyncListenerMap.put(action, eventBus);
            } else {
                eventBus = listenerMap.get(action);
                if (null == eventBus) {
                    eventBus = new EventBus();
                }
                listenerMap.put(action, eventBus);
            }

            eventBus.register(listenerClass);
        }
//        if (JFinal.me().getConstants().getDevMode()) {
//            //Printer.print(this, "event"(String.format("listener[%s]-->>registered.", listener));
//        }
    }

    public void unregister(Class<? extends IEventListener> listenerClass) {
        deleteListner(listenerMap, listenerClass);
        deleteListner(asyncListenerMap, listenerClass);
//        if (JFinal.me().getConstants().getDevMode()) {
//            //Printer.print(this, "event"(String.format("listener[%s]-->>unRegisterListener.", listenerClass));
//        }
    }

    @Override
    public void dispatch(IEvent event) {
        String action = null;
        if(event instanceof Event) {
            Event event1 = (Event) event;
            action = event1.getAction();
        } else {
            action = event.getClass().getName();
        }
        IEventBus eventBus = listenerMap.get(action);
        if (eventBus != null) {
            eventBus.post(event);
        }
        IEventBus asyncEventBus = asyncListenerMap.get(action);
        if (asyncEventBus != null) {
            asyncEventBus.post(event);
        }
    }

    private void deleteListner(Map<String, IEventBus> map, Class<? extends IEventListener> listenerClass) {
        for (Map.Entry<String, IEventBus> entry : map.entrySet()) {
            IEventBus eventBus = entry.getValue();
            if(eventBus != null) {
                eventBus.unregister(listenerClass);
            }
        }
    }
}
